from collections import deque
import pandas as pd
from keywordutil import AhoCorasick

# 单位性质	职能类型	优先级	省级称呼	地市级称呼	县级称呼	乡级称呼	关键词	必备前缀	必备后缀
class RuleItem:
    def __init__(self):
        self.nature = '' # 单位性质
        self.duty = '' # 职能类型
        self.priority = 80 # 优先级
        self.l1_name = '' # 省级称呼
        self.l2_name = '' # 地市级称呼
        self.l3_name = '' # 县级称呼
        self.l4_name = '' # 乡级称呼
        self.keyword_list = [] # 关键词
        self.prefix_list = [] # 必备前缀
        self.suffix_list = [] # 必备后缀

    def __repr__(self):
        # 完善打印信息，显示所有属性
        return (f"RuleItem(\n"
                f"  nature='{self.nature}',\n"
                f"  duty='{self.duty}',\n"
                f"  priority={self.priority},\n"
                f"  l1_name='{self.l1_name}',\n"
                f"  l2_name='{self.l2_name}',\n"
                f"  l3_name='{self.l3_name}',\n"
                f"  l4_name='{self.l4_name}',\n"
                f"  keyword_list={self.keyword_list},\n"
                f"  prefix_list={self.prefix_list},\n"
                f"  suffix_list={self.suffix_list}\n"
                f")")

class OrgTypeMatch:
    def __init__(self):
        self.aho = AhoCorasick()
    
    def load_keywords(self):
        # 步骤1：读取Excel文件并构建rule_list
        print("步骤1：读取Excel文件并构建规则列表...")
        # 读取Excel文件
        df = pd.read_excel('机构类型识别关键词.xlsx')
        
        # 检查必要的列是否存在
        required_columns = ['单位性质', '职能类型', '优先级', '省级称呼', '地市级称呼', 
                           '县级称呼', '乡级称呼', '关键词', '必备前缀', '必备后缀']
        for col in required_columns:
            if col not in df.columns:
                raise ValueError(f"Excel文件缺少必要的列：{col}")
        
        rule_list = []
        # 遍历每一行构建RuleItem
        for _, row in df.iterrows():
            rule_item = RuleItem()
            rule_item.nature = str(row['单位性质']) if pd.notna(row['单位性质']) else ''
            rule_item.duty = str(row['职能类型']) if pd.notna(row['职能类型']) else ''
            rule_item.priority = 20 if pd.notna(row['优先级']) and '低'==row['优先级'] else 80
            rule_item.l1_name = str(row['省级称呼']) if pd.notna(row['省级称呼']) else ''
            rule_item.l2_name = str(row['地市级称呼']) if pd.notna(row['地市级称呼']) else ''
            rule_item.l3_name = str(row['县级称呼']) if pd.notna(row['县级称呼']) else ''
            rule_item.l4_name = str(row['乡级称呼']) if pd.notna(row['乡级称呼']) else ''
            
            # 处理关键词列表（可能包含多个，用|分隔）
            keywords = str(row['关键词']) if pd.notna(row['关键词']) else ''
            rule_item.keyword_list = [k.strip() for k in keywords.split('|') if k.strip()]
            
            # 处理必备前缀列表
            prefixes = str(row['必备前缀']) if pd.notna(row['必备前缀']) else ''
            rule_item.prefix_list = [p.strip() for p in prefixes.split('|') if p.strip()]
            
            # 处理必备后缀列表
            suffixes = str(row['必备后缀']) if pd.notna(row['必备后缀']) else ''
            rule_item.suffix_list = [s.strip() for s in suffixes.split('|') if s.strip()]
            
            rule_list.append(rule_item)
        
        print(f"成功构建{len(rule_list)}条规则")
        
        # 添加所有关键词到Aho-Corasick
        keyword_count = 0
        for rule in rule_list:
            for keyword in rule.keyword_list:
                self.aho.add_pattern(keyword, rule)
                keyword_count += 1
        
        print(f"已添加{keyword_count}个关键词到自动机")
        
        # 构建失败指针
        self.aho.build()
        print("Aho-Corasick自动机构建完成")
        
    def _check_prefix(self, address, keyword, prefix_list):
        """检查前缀是否符合要求"""
        if not prefix_list or len(prefix_list) == 0:
            return True
            
        keyword_pos = address.find(keyword)
        if keyword_pos == -1:
            return False
            
        # 检查是否有一个前缀出现在关键词之前
        for prefix in prefix_list:
            prefix_pos = address.find(prefix)
            if prefix_pos != -1 and prefix_pos <= keyword_pos:
                return True
                
        return False
    
    def _check_suffix(self, address, keyword, suffix_list):
        """检查后缀是否符合要求"""
        if not suffix_list or len(suffix_list) == 0:
            return True
            
        keyword_pos = address.find(keyword)
        if keyword_pos == -1:
            return False
            
        keyword_end_pos = keyword_pos + len(keyword)
        
        # 检查是否有一个后缀出现在关键词之后
        for suffix in suffix_list:
            suffix_pos = address.find(suffix)
            if suffix_pos != -1 and suffix_pos >= keyword_end_pos:
                return True
                
        return False
        
    def get_best_match(self, address):
        results = self.aho.search(address)
        #print('--', results)
        if not results:
            # print("未找到任何匹配的关键词")
            return (None, None, None, None, None, None)
        
        # 过滤符合前缀后缀要求的规则
        valid_matches = []
        for keyword, rule in results:
            # 检查前缀条件
            prefix_ok = self._check_prefix(address, keyword, rule.prefix_list)
            # 检查后缀条件
            suffix_ok = self._check_suffix(address, keyword, rule.suffix_list)
            
            if prefix_ok and suffix_ok:
                valid_matches.append((keyword, rule))
        
        if not valid_matches:
            #print("没有找到符合前缀后缀要求的匹配项")
            return (None, None, None, None, None, None)
        
        # 排序：先按优先级降序，再按关键词长度降序
        valid_matches.sort(
            key=lambda x: (-x[1].priority, len(x[0])),
            reverse=False
        )
        
        # 打印所有有效匹配项
        #for i, (keyword, rule) in enumerate(valid_matches, 1):
        #    print(f"有效匹配项 {i}:")
        #    print(f"  匹配关键词: {keyword} (长度: {len(keyword)})")
        #    print(f"  优先级: {rule.priority}")
        #    print(f"  对应规则: {rule}")
        
      
        # 返回最佳匹配（第一个）
        best_keyword, best_rule = valid_matches[0]
        return (best_rule.nature, best_rule.duty, best_rule.l1_name, 
                best_rule.l2_name, best_rule.l3_name, best_rule.l4_name)


if __name__ == "__main__":
    org_type_matcher = OrgTypeMatch()
    org_type_matcher.load_keywords()
    result = org_type_matcher.get_best_match('阿克苏地区国家安全局')
    nature, duty, l1_name, l2_name, l3_name, l4_name = result
    print(f"匹配结果: {result}; 性质:{nature}")    
